package ssdb

import (
	"bytes"
	"encoding/json"
	"errors"
	"time"

	"github.com/seefan/gossdb/v2/pool"

	"strings"
)

//SSdbRepository SSDB 仓储(string)
type SSdbRepository struct {
	pool       *pool.Connectors
	entityName string
	timeout    time.Duration
}

//getKey 获取key
func (s *SSdbRepository) getKey(key string) string {
	buf := strings.Builder{}
	buf.WriteString(s.entityName)
	buf.WriteString(":")
	buf.WriteString(key)
	return buf.String()
}

//getHKey 获取Incr递增字段特殊key
func (s *SSdbRepository) getHKey(key string) string {
	return s.CreateKey("Incr",key)
}

//CreateKey 创建内部key
func (s *SSdbRepository) CreateKey(prefix,key string) string  {
	buf := strings.Builder{}
	buf.WriteString(prefix)
	buf.WriteString(":")
	buf.WriteString(s.entityName)
	buf.WriteString(":")
	buf.WriteString(key)
	return buf.String()
}

// Set 插入单个[key数据存在会更新]
// entity  	   结构体
// ttl         单位秒 ，0为永不到期
func (s *SSdbRepository) Set(key string, entity interface{}, ttl int64) (int64, error) {
	keyStr := s.getKey(key)
	//序列化
	val, err := json.Marshal(entity)
	if err != nil {
		return 0, err
	}
	client,err := s.pool.NewClient()
	if err != nil{
		return 0, err
	}
	defer client.Close()
	if ttl > 0 {
		err = client.Set(keyStr, string(val), ttl)
	} else {
		err = client.Set(keyStr, string(val))
	}
	if err != nil {
		return 0, err
	}
	return 1, nil
}


// SetMany 插入多个    [key数据存在会更新]
// entityMap   结构体字典
func (s *SSdbRepository) SetMany(entityMap map[string]interface{}) (int64, error) {
	dataMap := make(map[string]interface{},len(entityMap))
	for key, val := range entityMap {
		valBt, err := json.Marshal(val)
		if err != nil {
			return 0, err
		}
		dataMap[s.getKey(key)] = string(valBt)
	}
	client,err := s.pool.NewClient()
	if err != nil{
		return 0, err
	}
	defer client.Close()
	err = client.MultiSet(dataMap)
	if err != nil {
		return 0, err
	}
	return int64(len(dataMap)), nil
}

//Incr 递增
func (s *SSdbRepository) Incr(key ,field string,num int64) (int64,error) {
	client,err := s.pool.NewClient()
	if err != nil{
		return 0, err
	}
	defer client.Close()
	keyStr := s.getHKey(key)
	return client.HIncr(keyStr, field, num)
}

//RemoveIncr 清理递增字段
func (s *SSdbRepository) RemoveIncr(key string) error {
	client, err := s.pool.NewClient()
	if err != nil {
		return err
	}
	defer client.Close()
	keyStr := s.getHKey(key)
	err = client.HClear(keyStr)
	if err != nil {
		return err
	}
	return nil
}

//GetIncr 获取递增值
func (s *SSdbRepository) GetIncr(key string,res map[string]int64) (err error) {
	keyStr := s.getHKey(key)
	client, err := s.pool.NewClient()
	if err != nil {
		return err
	}
	defer client.Close()
	fields := make([]string, 0, len(res))
	for key, _ := range res {
		fields = append(fields, key)
	}
	qRes, err := client.MultiHGet(keyStr, fields...)
	if err != nil {
		return err
	}
	for key, _ := range res {
		value := qRes[key]
		if value.IsEmpty() {
			continue
		}
		res[key] = value.Int64()
	}
	return nil
}


// Remove 移除
// keys key值切片
func (s *SSdbRepository) Remove(keys ...string) (int64, error) {
	keySlice := make([]string, 0, len(keys))
	for _, val := range keys {
		keySlice = append(keySlice, s.getKey(val))
	}
	client, err := s.pool.NewClient()
	if err != nil {
		return 0, err
	}
	defer client.Close()
	err = client.MultiDel(keySlice...)
	if err != nil {
		return 0, err
	}
	return int64(len(keySlice)), nil
}

//Get 查询单个
// key         key值
// result      查询的结果
func (s *SSdbRepository) Get(key string, result interface{}) error {
	keyStr := s.getKey(key)

	client,err := s.pool.NewClient()
	if err != nil{
		return err
	}
	defer client.Close()

	value, err := client.Get(keyStr)
	if err != nil {
		return err
	}

	if value.IsEmpty() {
		return errors.New("SSDB:nil")
	}

	err = json.Unmarshal(value.Bytes(), result)
	if err != nil{
		return err
	}
	return nil
}

//GetMany 查询多个
// keys        key值切片
// result      查询的结果切片
func (s *SSdbRepository) GetMany(keys []string, result interface{}) error {
	keySlice := make([]string,0,len(keys))
	for _,val := range keys {
		keySlice = append(keySlice, s.getKey(val))
	}
	client,err := s.pool.NewClient()
	if err != nil{
		return err
	}
	defer client.Close()

	resMap, err := client.MultiGet(keySlice...)
	if err != nil{
		return err
	}
	var count = len(keySlice)
	var buf = bytes.Buffer{}
	buf.WriteString("[")
	for _,val := range keySlice {
		value, ok := resMap[val]
		if ok && !value.IsEmpty() {
			buf.WriteString(value.String())
		} else {
			buf.WriteString("{}")
		}
		count--
		if count > 0  {
			buf.WriteString(",")
		}
	}
	buf.WriteString("]")
	err = json.Unmarshal(buf.Bytes(), result)
	if err != nil{
		return err
	}
	return nil
}

//Do 直接执行
func (s *SSdbRepository) Do(h func(*pool.Client))  error {
	client, err := s.pool.NewClient()
	if err != nil {
		return err
	}
	defer client.Close()
	h(client)
	return nil
}